package zzps.exeed.kernel.core;

import zzps.exeed.kernel.tool.ResourceTool;

import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Predicate;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public abstract class ClassPathScanner {
    protected ClassLoader classLoader;
    protected Predicate<String> fileFilter;
    List<String> fileList = new LinkedList<>();

    public ClassPathScanner(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    public void setFileFilter(Predicate<String> fileFilter) {
        this.fileFilter = fileFilter;
    }

    protected List<String> doScan(String... paths){
        for (String path : paths) {
            Enumeration<URL> enumeration = ResourceTool.getResources(path, classLoader);
            Iterator<URL> iterator = enumeration.asIterator();
            while (iterator.hasNext()){
                URL url = iterator.next();
                String protocol = url.getProtocol();
                if ("file".equals(protocol)){
                    scanFile(new File(URLDecoder.decode(url.getFile(), StandardCharsets.UTF_8)), path);
                }else if ("jar".equals(protocol)){
                    JarFile jarFile = null;
                    try {
                        jarFile = ((JarURLConnection) url.openConnection()).getJarFile();
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                    scanJar(jarFile,path);
                }
            }
        }
        return fileList;
    }
    private void scanFile(File rootFile, String path) {
        File[] files = rootFile.listFiles(f -> f.isDirectory() || fileFilter.test(f.getName()));
        for (File file : files) {
            String _path = path + "/" + file.getName();
            if (file.isFile()) {
                fileList.add(_path);
            } else if (file.isDirectory()) {
                scanFile(file,_path);
            }
        }

    }
    private void scanJar(JarFile jar,String path) {
        Enumeration<JarEntry> enumeration = jar.entries();
        Iterator<JarEntry> iterator = enumeration.asIterator();
        while (iterator.hasNext()){
            JarEntry jarEntry = iterator.next();
            String name = jarEntry.getName();
            if (!name.startsWith(path)){
                continue;
            }
            if (jarEntry.isDirectory()){
                continue;
            }
            if (fileFilter != null && fileFilter.test(name)){
                fileList.add(name);
            }
        }
    }
}
